﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Syndication;
using System.Xml;
using System.Xml.Linq;

using GeoSyndication.Common;

namespace GeoSyndication.KML
{
    public class KMLFeedBuilder
    {
        #region Private Fields

        public static Dictionary<Type, Func<KMLItem, SyndicationItem>> Formatters = new Dictionary<Type, Func<KMLItem, SyndicationItem>>();

        #endregion

        #region Constructor

        static KMLFeedBuilder()
        {
            Formatters.Add(typeof(KMLLineItem), i => GetLineItem((i as KMLLineItem)));
            Formatters.Add(typeof(KMLPointItem), i => GetPointItem((i as KMLPointItem)));
            Formatters.Add(typeof(KMLPolygonItem), i => GetPolygonItem((i as KMLPolygonItem)));
            Formatters.Add(typeof(KMLItem), i => GetItem((i as KMLItem)));
        } 

        #endregion

        #region Public Methods

        public static SyndicationFeed GetFeed(KMLData builder)
        {
            if (builder == null)
            {
                throw new ArgumentException("You must provide GeoRSSdata");
            }

            SyndicationFeed feed = new SyndicationFeed(builder.Title, builder.Description, null);

            List<SyndicationItem> items = new List<SyndicationItem>();

            builder.Items.ForEach(item =>
            {
                items.Add(Formatters[item.GetType()].Invoke(item));
            });

            feed.Items = items;

            return feed;
        }

        #endregion

        #region Private Members

        private static SyndicationItem GetItem(KMLItem pointItem)
        {
            SyndicationItem sy_item = BuildItem(pointItem.Title, pointItem.Description, pointItem.Icon, pointItem.Link, pointItem.Categories, pointItem.Date);
            return sy_item;
        }

        private static SyndicationItem GetPointItem(KMLPointItem pointItem)
        {
            SyndicationItem sy_item = BuildItem(pointItem.Title, pointItem.Description, pointItem.Icon, pointItem.Link, pointItem.Categories, pointItem.Date);
            XElement x = new XElement("Point");
            x.Add(new XElement("coordinates", pointItem.ToString()));
            SyndicationElementExtension sext = new SyndicationElementExtension(x);
            sy_item.ElementExtensions.Add(new SyndicationElementExtension(x));
            return sy_item;
        }

        private static SyndicationItem GetPolygonItem(KMLPolygonItem polygonItem)
        {
            SyndicationItem sy_item = BuildItem(polygonItem.Title, polygonItem.Description, polygonItem.Icon, polygonItem.Link, polygonItem.Categories, polygonItem.Date);

            XElement polygon = new XElement("Polygon");
            XElement outerBoundaryIs = new XElement("outerBoundaryIs");
            XElement linearRing = new XElement("LinearRing");
            XElement coordinates = new XElement("coordinates", Utility.GetSequenceOfPoints(polygonItem.Polygon));
            polygon.Add(outerBoundaryIs);
            outerBoundaryIs.Add(linearRing);
            linearRing.Add(coordinates);
            sy_item.ElementExtensions.Add(new SyndicationElementExtension(polygon));

            return sy_item;
        }

        private static SyndicationItem GetLineItem(KMLLineItem lineItem)
        {
            SyndicationItem sy_item = BuildItem(lineItem.Title, lineItem.Description, lineItem.Icon, lineItem.Link, lineItem.Categories, lineItem.Date);

            XElement lineString = new XElement("LineString");
            XElement coordinates = new XElement("coordinates", Utility.GetSequenceOfPoints(lineItem.Line));
            lineString.Add(coordinates);
            sy_item.ElementExtensions.Add(new SyndicationElementExtension(lineString));

            return sy_item;
        }

        private static SyndicationItem BuildItem(string title, string description, string icon, string link, string[] categories, DateTime date)
        {
            SyndicationItem sy_item = new SyndicationItem(title, description, Utility.CreateUri(link));
            sy_item.PublishDate = date;
            Utility.BindCategories(categories, sy_item);

            /*
            if (!string.IsNullOrEmpty(icon))
            {
                sy_item.ElementExtensions.Add(AddIcon(icon));
            }
            if (!string.IsNullOrEmpty(link))
            {
                sy_item.ElementExtensions.Add(AddLink(link));
            }
            */

            return sy_item;
        }

        /*
        private static SyndicationElementExtension AddLink(string link)
        {
            XElement x = new XElement("link", link);
            //XElement x = new XElement("link", new XAttribute( "href", link ) );
            return new SyndicationElementExtension(x);
        }

        private static SyndicationElementExtension AddIcon(string icon)
        {
            XElement x = new XElement("icon", icon);
            return new SyndicationElementExtension(x);
        }

        */

        #endregion
    }
}
